﻿using System;
using System.IO.Ports;
using Vtron.ATSP.DomainObjects;
using Vtron.ATSP.Infrastructure;

namespace Vtron.ATSP.Tester
{
    /// <summary>
    /// 串口通信接口
    /// </summary>
    /// <remarks>
    ///     <创建人>邓穗捷</创建人>
    ///     <创建时间>2014-08-14</创建时间>
    ///     <修订人></修订人>
    ///     <修订时间></修订时间>
    ///     <修订说明></修订说明>
    /// </remarks>
    public class SerialCom : ISerialCom
    {
        #region Fields

        ISerialHandler serialHandler;

        #endregion

        #region Constructors

        /// <summary>
        /// 无参的构造函数
        /// </summary>
        /// <remarks>
        ///     <创建人>邓穗捷</创建人>
        ///     <创建时间>2014-08-22</创建时间>
        ///     <修订人></修订人>
        ///     <修订时间></修订时间>
        ///     <修订说明></修订说明>
        /// </remarks>
        public SerialCom()
            : this(new SerialHandler())
        {
        }

        /// <summary>
        /// 带一个参数的共有构造函数
        /// </summary>
        /// <param name="serialHandler">串口通信接口</param>
        /// <remarks>
        ///     <创建人>邓穗捷</创建人>
        ///     <创建时间>2014-08-22</创建时间>
        ///     <修订人></修订人>
        ///     <修订时间></修订时间>
        ///     <修订说明></修订说明>
        /// </remarks>
        public SerialCom(ISerialHandler serialHandler)
        {
            this.serialHandler = serialHandler;
        }

        #endregion

        /// <summary>
        /// 检查端口连接
        /// </summary>
        /// <returns>
        /// 是否连接成功 
        ///     true:成功
        ///     false:失败
        /// </returns>
        /// <remarks>
        ///     <创建人>邓穗捷</创建人>
        ///     <创建时间>2014-08-22</创建时间>
        ///     <修订人></修订人>
        ///     <修订时间></修订时间>
        ///     <修订说明></修订说明>
        /// </remarks>
        public bool CheckCOM()
        {
            bool result = false;

            result = serialHandler.CheckCOM(Utils.TesterPortName, Utils.TesterBaudRate);

            return result;
        }

        /// <summary>
        /// 设置ADC参数指令
        ///     PC to MCU
        ///         0	帧同步头1：  0xAA
        ///         1	帧同步头2：  0x88
        ///         2	帧同步头3：  0x19
        ///         3	设备号：     XX (已知)
        ///         4	命令字：     0x0E
        ///         5	Payload长度：0x4
        ///         6	操作码：     0x1（配置）
        ///         7	状态码：     00 
        ///         8	净荷：       XX（参考电流）
        ///         9	净荷：       XX（积分时间）
        ///         10	帧序号：     0
        ///         11	校验和：     XX
        ///     MCU to PC
        ///         0	帧同步头1：  0x55
        ///         1	帧同步头2：  0x88
        ///         2	帧同步头3：  0x19
        ///         3	设备号：     XX(已知)
        ///         4	命令字：     0x0E
        ///         5	Payload长度：0x04
        ///         6	操作码：     0x01（配置）
        ///         7	状态码：     XX （0x0-成功；0xFF-失败）
        ///         8	净荷：       XX（参考电流返回）
        ///         9	净荷：       XX（积分时间返回）
        ///         10	帧序号：     0
        ///         11	校验和：     XX
        /// </summary>
        /// <param name="range">量程参数</param>
        /// <returns>
        /// 是否设置成功 
        ///     true:成功
        ///     false:失败
        /// </returns>
        public bool SetADC(Range range)
        {
            bool result = false;

            byte[] sendData = new byte[12];
            sendData[0] = 0xAA;
            sendData[1] = 0x88;
            sendData[2] = 0x19;
            sendData[3] = range.DeviceNum;
            sendData[4] = 0x0E;
            sendData[5] = 0x4;
            sendData[6] = 0x1;
            sendData[7] = 0x0;
            sendData[8] = range.ReferCurrent;
            sendData[9] = range.IntegrationPeriod;
            sendData[10] = 0x0;

            byte sum = 0;
            foreach (byte b in sendData)
            {
                sum += b;
            }
            sendData[11] = sum;

            byte[] receivedData = serialHandler.Send(Utils.TesterPortName, Utils.TesterBaudRate, Utils.TesterParity, Utils.TesterDataBits, Utils.TesterStopBits, Utils.TesterReadTimeout, sendData);

            if (receivedData.Length != 12)
            {
                throw new ATSPException(String.Format("获取ADC-SENSOR数据失败！测试仪返回了错误的数据长度{0}", receivedData.Length));
            }

            if (receivedData[7] == 0)
            {
                result = true;
            }
            else if (receivedData[7] == 0xFF)
            {
                result = false;
            }
            else
            {
                throw new ATSPException(String.Format("设置ADC参数失败！错误状态码：{0}", receivedData[7]));
            }

            return result;
        }

        /// <summary>
        /// 获取ADC-SENSOR数据指令
        ///     PC to MCU
        ///         0	帧同步头1：  0xAA
        ///         1	帧同步头2：  0x88
        ///         2	帧同步头3：  0x19
        ///         3	设备号：     XX (已知)
        ///         4	命令字：     0x0F
        ///         5	Payload长度：0x2
        ///         6	操作码：     0x0
        ///         7	状态码：     00 
        ///         8	帧序号：     0
        ///         9	校验和：     XX
        ///     MCU to PC
        ///         0	帧同步头1：  0x55
        ///         1	帧同步头2：  0x88
        ///         2	帧同步头3：  0x19
        ///         3	设备号：     XX(已知)
        ///         4	命令字：     0x0E
        ///         5	Payload长度：0x05
        ///         6	操作码：     0x00（查询）
        ///         7	状态码：     XX （0x0-成功；0xFF-失败）
        ///         8	净荷：       XX（参考电流）
        ///         9	净荷：       XX（积分时间）
        ///         10	净荷：       XX（采集值高8位）
        ///         11	净荷：       XX（采集值低8位）
        ///         12	帧序号：     0
        ///         13	校验和：     XX
        /// </summary>
        /// <param name="deviceNum"></param>
        /// <returns>采集值</returns>
        public Sensor GetSensor(byte deviceNum)
        {
            byte[] sendData = new byte[10];
            sendData[0] = 0xAA;
            sendData[1] = 0x88;
            sendData[2] = 0x19;
            sendData[3] = deviceNum;
            sendData[4] = 0x0F;
            sendData[5] = 0x2;
            sendData[6] = 0x0;
            sendData[7] = 0x0;
            sendData[8] = 0x0;

            byte sum = 0;
            foreach (byte b in sendData)
            {
                sum += b;
            }
            sendData[9] = sum;

            byte[] receivedData = serialHandler.Send(Utils.TesterPortName, Utils.TesterBaudRate, Utils.TesterParity, Utils.TesterDataBits, Utils.TesterStopBits, Utils.TesterReadTimeout, sendData);

            if (receivedData.Length != 14)
            {
                throw new ATSPException(String.Format("获取ADC-SENSOR数据失败！测试仪返回了错误的数据长度{0}", receivedData.Length));
            }

            if (receivedData[7] != 0x00)
            {
                throw new ATSPException(String.Format("获取ADC-SENSOR数据失败！错误状态码：{0}", receivedData[7]));
            }

            if (receivedData[3] != deviceNum)
            {
                throw new ATSPException(String.Format("获取ADC-SENSOR数据失败！返回的设备号：{0}与预期的{1}不符合", receivedData[7], deviceNum));
            }

            Sensor sensor = new Sensor();
            sensor.DeviceNum = receivedData[3];
            sensor.ReferCurrent = receivedData[8];
            sensor.IntegrationPeriod = receivedData[9];
            sensor.CollectionValue = (ushort)(receivedData[10] * 256 + receivedData[11]);

            return sensor;
        }
    }
}
